# -*- coding: utf-8 -*-
"""
图片转换器
支持各种图片格式的互转和图片转PDF
"""

import os
from PIL import Image
from pathlib import Path


class ImageConverter:
    """图片转换器类"""

    def __init__(self):
        pass

    def convert(self, input_path, output_dir, conversion_type):
        """
        转换图片
        :param input_path: 输入文件路径
        :param output_dir: 输出目录
        :param conversion_type: 转换类型
        :return: 输出文件路径
        """
        if conversion_type == 'png_to_jpg':
            return self.png_to_jpg(input_path, output_dir)
        elif conversion_type == 'jpg_to_png':
            return self.jpg_to_png(input_path, output_dir)
        elif conversion_type == 'bmp_to_jpg':
            return self.bmp_to_jpg(input_path, output_dir)
        elif conversion_type == 'image_to_pdf':
            return self.image_to_pdf(input_path, output_dir)
        elif conversion_type == 'webp_to_png':
            return self.webp_to_png(input_path, output_dir)
        elif conversion_type == 'webp_to_jpg':
            return self.webp_to_jpg(input_path, output_dir)
        elif conversion_type == 'png_to_webp':
            return self.png_to_webp(input_path, output_dir)
        elif conversion_type == 'jpg_to_webp':
            return self.jpg_to_webp(input_path, output_dir)
        elif conversion_type == 'svg_to_png':
            return self.svg_to_png(input_path, output_dir)
        elif conversion_type == 'png_to_svg':
            return self.png_to_svg(input_path, output_dir)
        else:
            raise ValueError(f"不支持的转换类型: {conversion_type}")

    def png_to_jpg(self, png_path, output_dir):
        """
        PNG转JPG - 高质量转换，智能处理透明背景
        :param png_path: PNG文件路径
        :param output_dir: 输出目录
        :return: 输出文件路径
        """
        if not os.path.exists(png_path):
            raise FileNotFoundError(f"文件不存在: {png_path}")

        if not png_path.lower().endswith('.png'):
            raise ValueError(f"不是PNG文件: {png_path}")

        base_name = os.path.splitext(os.path.basename(png_path))[0]
        output_path = os.path.join(output_dir, f"{base_name}.jpg")

        try:
            # 打开PNG图片
            img = Image.open(png_path)

            print(f"原始图片: {img.size[0]}x{img.size[1]}, 模式: {img.mode}")

            # 如果图片有透明通道，需要先转换为RGB
            if img.mode in ('RGBA', 'LA', 'P'):
                # 创建白色背景
                background = Image.new('RGB', img.size, (255, 255, 255))
                if img.mode == 'P':
                    img = img.convert('RGBA')

                # 智能合成：保留透明度信息
                if 'transparency' in img.info:
                    background.paste(img, (0, 0), img)
                elif img.mode == 'RGBA':
                    background.paste(img, (0, 0), img.split()[-1])
                else:
                    background.paste(img, (0, 0))

                img = background
                print("已将透明背景转换为白色背景")
            elif img.mode != 'RGB':
                img = img.convert('RGB')

            # 高质量保存
            # quality: 95 (高质量), optimize: True (优化文件大小), subsampling: 0 (最佳质量)
            img.save(
                output_path,
                'JPEG',
                quality=98,  # 非常高的质量
                optimize=True,  # 优化编码
                progressive=True,  # 渐进式JPEG
                subsampling=0  # 4:4:4色度子采样（最佳质量）
            )

            print(f"✓ 转换成功: {os.path.basename(output_path)}")
        except Exception as e:
            raise Exception(f"PNG转JPG失败: {str(e)}")

        if not os.path.exists(output_path):
            raise Exception("转换失败，输出文件未生成")

        return output_path

    def jpg_to_png(self, jpg_path, output_dir):
        """
        JPG转PNG
        :param jpg_path: JPG文件路径
        :param output_dir: 输出目录
        :return: 输出文件路径
        """
        if not os.path.exists(jpg_path):
            raise FileNotFoundError(f"文件不存在: {jpg_path}")

        ext = jpg_path.lower()
        if not (ext.endswith('.jpg') or ext.endswith('.jpeg')):
            raise ValueError(f"不是JPG文件: {jpg_path}")

        base_name = os.path.splitext(os.path.basename(jpg_path))[0]
        output_path = os.path.join(output_dir, f"{base_name}.png")

        try:
            # 打开JPG图片
            img = Image.open(jpg_path)
            # 保存为PNG
            img.save(output_path, 'PNG')
        except Exception as e:
            raise Exception(f"JPG转PNG失败: {str(e)}")

        if not os.path.exists(output_path):
            raise Exception("转换失败，输出文件未生成")

        return output_path

    def bmp_to_jpg(self, bmp_path, output_dir):
        """
        BMP转JPG
        :param bmp_path: BMP文件路径
        :param output_dir: 输出目录
        :return: 输出文件路径
        """
        if not os.path.exists(bmp_path):
            raise FileNotFoundError(f"文件不存在: {bmp_path}")

        if not bmp_path.lower().endswith('.bmp'):
            raise ValueError(f"不是BMP文件: {bmp_path}")

        base_name = os.path.splitext(os.path.basename(bmp_path))[0]
        output_path = os.path.join(output_dir, f"{base_name}.jpg")

        try:
            # 打开BMP图片
            img = Image.open(bmp_path)
            # 转换为RGB模式（如果需要）
            if img.mode != 'RGB':
                img = img.convert('RGB')
            # 保存为JPG
            img.save(output_path, 'JPEG', quality=95)
        except Exception as e:
            raise Exception(f"BMP转JPG失败: {str(e)}")

        if not os.path.exists(output_path):
            raise Exception("转换失败，输出文件未生成")

        return output_path

    def image_to_pdf(self, image_path, output_dir):
        """
        单图转PDF - 高质量转换，保持图片分辨率和清晰度
        :param image_path: 图片文件路径
        :param output_dir: 输出目录
        :return: 输出PDF文件路径
        """
        base_name = os.path.splitext(os.path.basename(image_path))[0]
        output_path = os.path.join(output_dir, f"{base_name}.pdf")

        try:
            # 打开图片
            img = Image.open(image_path)

            print(f"原始图片: {img.size[0]}x{img.size[1]}, DPI: {img.info.get('dpi', 'unknown')}")

            # 转换为RGB模式（PDF需要）
            if img.mode in ('RGBA', 'LA'):
                # 处理透明背景
                background = Image.new('RGB', img.size, (255, 255, 255))
                if img.mode == 'RGBA':
                    background.paste(img, mask=img.split()[-1])
                else:
                    background.paste(img)
                img = background
            elif img.mode != 'RGB':
                img = img.convert('RGB')

            # 保存为高质量PDF
            # 保持原始DPI，如果没有则使用300 DPI
            dpi = img.info.get('dpi', (300, 300))
            if isinstance(dpi, tuple):
                dpi = dpi[0]

            img.save(
                output_path,
                'PDF',
                resolution=max(dpi, 150),  # 至少150 DPI
                quality=95,
                optimize=False  # 不压缩以保持质量
            )

            print(f"✓ 图片已转换为PDF (DPI: {max(dpi, 150)})")
        except Exception as e:
            raise Exception(f"图片转PDF失败: {str(e)}")

        return output_path

    def images_to_pdf(self, image_paths, output_dir):
        """
        多图合并为PDF - 高质量转换，保持所有图片清晰度
        :param image_paths: 图片文件路径列表
        :param output_dir: 输出目录
        :return: 输出PDF文件路径
        """
        if not image_paths:
            raise ValueError("图片列表为空")

        # 生成输出文件名
        output_path = os.path.join(output_dir, "merged_images.pdf")

        print(f"\n合并 {len(image_paths)} 张图片为PDF...")

        # 打开所有图片并处理
        processed_images = []
        for idx, img_path in enumerate(image_paths, 1):
            try:
                img = Image.open(img_path)
                print(f"[{idx}/{len(image_paths)}] {os.path.basename(img_path)}: {img.size[0]}x{img.size[1]}")

                # 处理透明背景和颜色模式
                if img.mode in ('RGBA', 'LA'):
                    background = Image.new('RGB', img.size, (255, 255, 255))
                    if img.mode == 'RGBA':
                        background.paste(img, mask=img.split()[-1])
                    else:
                        background.paste(img)
                    img = background
                elif img.mode != 'RGB':
                    img = img.convert('RGB')

                processed_images.append(img)
            except Exception as e:
                print(f"  ✗ 无法处理图片 {img_path}: {e}")

        if not processed_images:
            raise ValueError("没有有效的图片文件")

        # 保存为高质量PDF
        try:
            processed_images[0].save(
                output_path,
                save_all=True,
                append_images=processed_images[1:] if len(processed_images) > 1 else [],
                resolution=300,  # 高分辨率
                quality=95,
                optimize=False
            )

            print(f"\n✓ 成功合并 {len(processed_images)} 张图片为PDF")
            print(f"  输出文件: {os.path.basename(output_path)}")
        except Exception as e:
            raise Exception(f"合并图片为PDF失败: {str(e)}")

        return output_path

    def webp_to_png(self, webp_path, output_dir):
        """
        WebP转PNG
        :param webp_path: WebP文件路径
        :param output_dir: 输出目录
        :return: 输出文件路径
        """
        if not os.path.exists(webp_path):
            raise FileNotFoundError(f"文件不存在: {webp_path}")

        if not webp_path.lower().endswith('.webp'):
            raise ValueError(f"不是WebP文件: {webp_path}")

        base_name = os.path.splitext(os.path.basename(webp_path))[0]
        output_path = os.path.join(output_dir, f"{base_name}.png")

        print(f"\n开始转换: {os.path.basename(webp_path)}")

        try:
            # 打开WebP图片
            img = Image.open(webp_path)
            print(f"原始图片: {img.size[0]}x{img.size[1]}, 模式: {img.mode}")

            # 保存为PNG
            img.save(output_path, 'PNG')
            print("✓ WebP转PNG成功")

            return output_path

        except Exception as e:
            raise Exception(f"WebP转PNG失败: {str(e)}")

    def webp_to_jpg(self, webp_path, output_dir):
        """
        WebP转JPG
        :param webp_path: WebP文件路径
        :param output_dir: 输出目录
        :return: 输出文件路径
        """
        if not os.path.exists(webp_path):
            raise FileNotFoundError(f"文件不存在: {webp_path}")

        if not webp_path.lower().endswith('.webp'):
            raise ValueError(f"不是WebP文件: {webp_path}")

        base_name = os.path.splitext(os.path.basename(webp_path))[0]
        output_path = os.path.join(output_dir, f"{base_name}.jpg")

        print(f"\n开始转换: {os.path.basename(webp_path)}")

        try:
            # 打开WebP图片
            img = Image.open(webp_path)
            print(f"原始图片: {img.size[0]}x{img.size[1]}, 模式: {img.mode}")

            # 处理透明通道
            if img.mode in ('RGBA', 'LA', 'P'):
                background = Image.new('RGB', img.size, (255, 255, 255))
                if img.mode == 'P':
                    img = img.convert('RGBA')

                if 'transparency' in img.info:
                    background.paste(img, (0, 0), img)
                elif img.mode == 'RGBA':
                    background.paste(img, (0, 0), img.split()[-1])
                else:
                    background.paste(img, (0, 0))

                img = background
            elif img.mode != 'RGB':
                img = img.convert('RGB')

            # 高质量保存
            img.save(output_path, 'JPEG', quality=98, optimize=True, progressive=True, subsampling=0)
            print("✓ WebP转JPG成功")

            return output_path

        except Exception as e:
            raise Exception(f"WebP转JPG失败: {str(e)}")

    def png_to_webp(self, png_path, output_dir):
        """
        PNG转WebP - 高质量转换，保持透明度
        :param png_path: PNG文件路径
        :param output_dir: 输出目录
        :return: 输出文件路径
        """
        if not os.path.exists(png_path):
            raise FileNotFoundError(f"文件不存在: {png_path}")

        if not png_path.lower().endswith('.png'):
            raise ValueError(f"不是PNG文件: {png_path}")

        base_name = os.path.splitext(os.path.basename(png_path))[0]
        output_path = os.path.join(output_dir, f"{base_name}.webp")

        print(f"\n开始转换: {os.path.basename(png_path)}")

        try:
            # 打开PNG图片
            img = Image.open(png_path)
            print(f"原始图片: {img.size[0]}x{img.size[1]}, 模式: {img.mode}")

            # 保存为WebP（高质量，保持透明度）
            img.save(
                output_path,
                'WEBP',
                quality=95,  # 高质量
                method=6,    # 最佳压缩方法（0-6，6最慢但最好）
                lossless=False  # 有损压缩（文件更小）
            )
            print("✓ PNG转WebP成功")

            return output_path

        except Exception as e:
            raise Exception(f"PNG转WebP失败: {str(e)}")

    def jpg_to_webp(self, jpg_path, output_dir):
        """
        JPG转WebP
        :param jpg_path: JPG文件路径
        :param output_dir: 输出目录
        :return: 输出文件路径
        """
        if not os.path.exists(jpg_path):
            raise FileNotFoundError(f"文件不存在: {jpg_path}")

        ext = jpg_path.lower()
        if not (ext.endswith('.jpg') or ext.endswith('.jpeg')):
            raise ValueError(f"不是JPG文件: {jpg_path}")

        base_name = os.path.splitext(os.path.basename(jpg_path))[0]
        output_path = os.path.join(output_dir, f"{base_name}.webp")

        print(f"\n开始转换: {os.path.basename(jpg_path)}")

        try:
            # 打开JPG图片
            img = Image.open(jpg_path)
            print(f"原始图片: {img.size[0]}x{img.size[1]}, 模式: {img.mode}")

            # 保存为WebP
            img.save(output_path, 'WEBP', quality=95, method=6)
            print("✓ JPG转WebP成功")

            return output_path

        except Exception as e:
            raise Exception(f"JPG转WebP失败: {str(e)}")

    def svg_to_png(self, svg_path, output_dir, width=None, height=None):
        """
        SVG转PNG
        :param svg_path: SVG文件路径
        :param output_dir: 输出目录
        :param width: 输出宽度（像素），不指定则使用默认
        :param height: 输出高度（像素），不指定则使用默认
        :return: 输出文件路径
        """
        if not os.path.exists(svg_path):
            raise FileNotFoundError(f"文件不存在: {svg_path}")

        if not svg_path.lower().endswith('.svg'):
            raise ValueError(f"不是SVG文件: {svg_path}")

        base_name = os.path.splitext(os.path.basename(svg_path))[0]
        output_path = os.path.join(output_dir, f"{base_name}.png")

        print(f"\n开始转换: {os.path.basename(svg_path)}")
        print("=" * 60)

        # 方法1: 使用cairosvg（推荐）
        try:
            import cairosvg
            print("方法1: 使用 cairosvg - 高质量渲染...")

            # 设置输出参数
            kwargs = {'url': svg_path, 'write_to': output_path}
            if width:
                kwargs['output_width'] = width
            if height:
                kwargs['output_height'] = height
            else:
                # 默认使用较高的分辨率
                kwargs['scale'] = 2.0

            cairosvg.svg2png(**kwargs)

            if os.path.exists(output_path):
                print("✓ cairosvg转换成功")
                return output_path

        except ImportError:
            print("✗ cairosvg未安装")
        except Exception as e:
            print(f"✗ cairosvg转换失败: {str(e)}")

        # 方法2: 使用svglib + reportlab
        try:
            from svglib.svglib import svg2rlg
            from reportlab.graphics import renderPM

            print("\n方法2: 使用 svglib + reportlab...")

            drawing = svg2rlg(svg_path)
            if drawing:
                # 设置输出尺寸
                if width and height:
                    drawing.width = width
                    drawing.height = height
                    drawing.scale(width / drawing.minWidth(), height / drawing.height)
                elif width or height:
                    scale = (width / drawing.width) if width else (height / drawing.height)
                    drawing.width *= scale
                    drawing.height *= scale
                    drawing.scale(scale, scale)

                renderPM.drawToFile(drawing, output_path, fmt='PNG', dpi=300)

                print("✓ svglib转换成功")
                return output_path

        except ImportError:
            print("✗ svglib或reportlab未安装")
        except Exception as e:
            print(f"✗ svglib转换失败: {str(e)}")

        # 方法3: 使用wand（ImageMagick）
        try:
            from wand.image import Image as WandImage

            print("\n方法3: 使用 wand (ImageMagick)...")

            with WandImage(filename=svg_path) as img:
                if width or height:
                    img.resize(width or img.width, height or img.height)

                img.format = 'png'
                img.save(filename=output_path)

            print("✓ wand转换成功")
            return output_path

        except ImportError:
            print("✗ wand未安装或ImageMagick未安装")
        except Exception as e:
            print(f"✗ wand转换失败: {str(e)}")

        # 所有方法都失败
        print("\n" + "=" * 60)
        print("✗ SVG转PNG失败：所有转换方法都失败")
        print("\n建议安装以下库之一：")
        print("1. pip install cairosvg（推荐）")
        print("2. pip install svglib reportlab")
        print("3. pip install wand（需要先安装ImageMagick）")
        print("=" * 60)

        raise Exception("SVG转PNG失败：请安装cairosvg、svglib或wand库")

    def png_to_svg(self, png_path, output_dir):
        """
        PNG转SVG（矢量化）
        注意：这是将位图转换为矢量图，效果取决于图片内容
        :param png_path: PNG文件路径
        :param output_dir: 输出目录
        :return: 输出文件路径
        """
        if not os.path.exists(png_path):
            raise FileNotFoundError(f"文件不存在: {png_path}")

        if not png_path.lower().endswith('.png'):
            raise ValueError(f"不是PNG文件: {png_path}")

        base_name = os.path.splitext(os.path.basename(png_path))[0]
        output_path = os.path.join(output_dir, f"{base_name}.svg")

        print(f"\n开始转换: {os.path.basename(png_path)}")
        print("=" * 60)
        print("注意：位图转矢量图质量取决于原图内容")
        print("     简单图形（图标、logo）效果较好")
        print("     复杂图片（照片）建议使用专业工具")
        print("=" * 60)

        # 方法1: 使用potrace（最佳质量）
        try:
            import subprocess

            print("方法1: 使用 potrace - 专业矢量化工具...")

            # 先转换为PBM格式（potrace需要）
            temp_pbm = os.path.join(output_dir, f"{base_name}_temp.pbm")

            img = Image.open(png_path)
            # 转换为黑白图像
            img_bw = img.convert('1')
            img_bw.save(temp_pbm, 'PPM')

            # 调用potrace
            potrace_paths = ['potrace', r'C:\Program Files\potrace\potrace.exe']
            for potrace_path in potrace_paths:
                try:
                    subprocess.run(
                        [potrace_path, '-s', '-o', output_path, temp_pbm],
                        check=True,
                        capture_output=True
                    )

                    # 删除临时文件
                    if os.path.exists(temp_pbm):
                        os.remove(temp_pbm)

                    if os.path.exists(output_path):
                        print("✓ potrace转换成功")
                        return output_path
                except FileNotFoundError:
                    continue
                except Exception as e:
                    continue

            print("✗ potrace未安装或执行失败")

        except Exception as e:
            print(f"✗ potrace方法失败: {str(e)}")

        # 方法2: 使用PIL创建简单的SVG嵌入
        try:
            print("\n方法2: 创建SVG嵌入（备用方法）...")

            img = Image.open(png_path)
            width, height = img.size

            # 将PNG转换为base64
            import base64
            from io import BytesIO

            buffered = BytesIO()
            img.save(buffered, format="PNG")
            img_base64 = base64.b64encode(buffered.getvalue()).decode()

            # 创建SVG文件（嵌入PNG）
            svg_content = f'''<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
     width="{width}" height="{height}" viewBox="0 0 {width} {height}">
    <image width="{width}" height="{height}"
           xlink:href="data:image/png;base64,{img_base64}"/>
</svg>'''

            with open(output_path, 'w', encoding='utf-8') as f:
                f.write(svg_content)

            print("✓ SVG创建成功（嵌入式，非真正矢量化）")
            print("  注意：这是将PNG嵌入SVG，不是真正的矢量化")
            print("  建议安装potrace获得真正的矢量图")

            return output_path

        except Exception as e:
            print(f"✗ 备用方法失败: {str(e)}")
            raise Exception(f"PNG转SVG失败: {str(e)}")
